/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 * \file     Firewall_Ppc.c                                                                   *
 * \brief    Semidrive Firewall PPC Driver                                                              *
 *                                                                                                 *
 **************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************************************************
 *                                      Include header files                                       *
 **************************************************************************************************/
#if (defined(CFG_PLATFORM_MCAL))
#include "RegHelper.h"
#endif /** #if (defined(CFG_PLATFORM_MCAL)) */

#include "Firewall_Ppc_Ip.h"

/***************************************************************************************************
 *                                 Private Macro definition                                        *
 **************************************************************************************************/
/** \brief The offset address of the apbmux1 ppc register. */
#define PPC_APBMUX_BASE_OFFSET          ((uint32_t)0x10000U)
/** \brief The offset address of the ppc apbmux register for different apbmux*/
#define PPC_APBMUX_OFFSET(n)            ((uint32_t)(n)*0x1000U)

/** \brief The offset address of the ppc permission0 register for differet
 * peripherals or apb regions. */
#define PPC_DOM_PER0(n)                 ((uint32_t)(n)*0x10U)
/** \brief The offset address of the ppc permission1 register for differet
 * peripherals or apb regions. */
#define PPC_DOM_PER1(n)                 ((uint32_t)(0x04U + ((uint32_t)(n)*0x10U)))
/** \brief The offset address of the ppc permission2 register for differet
 * peripherals or apb regions. */
#define PPC_DOM_PER2(n)                 ((uint32_t)(0x08U + ((uint32_t)(n)*0x10U)))
/** \brief The offset address of the ppc permission3 register for differet
 * peripherals or apb regions. */
#define PPC_DOM_PER3(n)                 ((uint32_t)(0x0CU + ((uint32_t)(n)*0x10U)))

/** \brief The address of the ppc permission0 register for differet peripherals
 * or apb regions. */
#define FIREWALL_PPC_DOMPER0_ADDR(base, apbmuxId, ipId)                        \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER0(ipId))

/** \brief The address of the ppc permission1 register for differet peripherals
 * or apb regions. */
#define FIREWALL_PPC_DOMPER1_ADDR(base, apbmuxId, ipId)                        \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET  +                              \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER1(ipId))

/** \brief The address of the ppc permission2 register for differet peripherals
 * or apb regions. */
#define FIREWALL_PPC_DOMPER2_ADDR(base, apbmuxId, ipId)                        \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET  +                              \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER2(ipId))

/** \brief The address of the ppc permission3 register for differet peripherals
 * or apb regions. */
#define FIREWALL_PPC_DOMPER3_ADDR(base, apbmuxId, ipId)                        \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET  +                              \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER3(ipId))

/** \brief The offset address of the ppc permission lock register for differet
 * peripherals or apb regions. */
#define PPC_DOM_PER_LOCK(n)             ((uint32_t)(0x500U + ((uint32_t)(n)*0x04U)))
/** \brief The bit mask of locking permission configurations. */
#define PPC_PERMISSION_LOCK_MASK        ((uint32_t)(0xFFFFUL))

/** \brief The address of the ppc permission lock register for differet
 * peripherals or apb regions. */
#define FIREWALL_PPC_DOM_PER_LOCK_ADDR(base, apbmuxId, ipId)                   \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER_LOCK(ipId))

/** \brief The offset address of the start address register for different apb
 * regions. */
#define PPC_RGN_START_ADDR(n)           ((uint32_t)(0x640U + ((uint32_t)(n)*0x0CU)))
/** \brief The offset bit of the start address of the apb region. */
#define PPC_RGN_START_ADDR_BIT          (12U)
/** \brief The width of the start address of the apb region. */
#define PPC_RGN_START_ADDR_WIDTH        (18U)
/** \brief The address of the start address register for different apb regions.
 */
#define FIREWALL_PPC_RGN_START_REG_ADDR(base, apbmuxId, regionId)              \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_RGN_START_ADDR(regionId))

/** \brief The offset address of the end address register for different apb
 * regions. */
#define PPC_RGN_END_ADDR(n)             ((uint32_t)(0x644U + ((uint32_t)(n)*0x0CU)))
/** \brief The offset bit of the end address of the apb region. */
#define PPC_RGN_END_ADDR_BIT            (12U)
/** \brief The width of the end address of the apb region. */
#define PPC_RGN_END_ADDR_WIDTH          (18U)
/** \brief The bit mask of locking address range of the apb region. */
#define PPC_RGN_END_ADDR_LOCK           ((uint32_t)(1UL << 31U))
/** \brief The bit mask of locking address range of the apb region. */
#define PPC_RGN_END_ADDR_LOCK_BIT       (31U)
/** \brief The address of the end address register for different apb regions. */
#define FIREWALL_PPC_RGN_END_REG_ADDR(base, apbmuxId, regionId)                \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_RGN_END_ADDR(regionId))

/** \brief Support 18 bits address, ADDR[29:12] */
#define PPC_REGION_ADDR(addr)           (((uint32_t)(addr) >> 12U) & 0x3FFFFU)

/** \brief The offset address of the region enable register for different apb
 * regions. */
#define PPC_RGN_ADDR_ENABLE(n)          ((uint32_t)(0x648U + ((uint32_t)(n)*0x0CU)))
/** \brief The start bit of locking region enable configuration. */
#define PPC_RGN_ENABLE_LOCK             ((uint32_t)(1UL << 31U))
/** \brief The start bit of locking region enable configuration in reverse. */
#define PPC_RGN_ENABLE_LOCK_INV         (30U)
/** \brief The bit mask of enabling region configuration in reverse. */
#define PPC_RGN_ENABLE_INV              (1U)
/** \brief The bit mask of enabling region configuration. */
#define PPC_RGN_ENABLE                  (0U)
/** \brief The address of the region enable register for different apb regions.
 */
#define FIREWALL_PPC_RGN_ADDR_ENABLE_REG_ADDR(base, apbmuxId, regionId)        \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_RGN_ADDR_ENABLE(regionId))

/** \brief The offset address of the response error disable register. */
#define PPC_RESP_ERR_DIS_OFFSET         ((uint32_t)0x714U)
/** \brief The bit mask of locking the response error disable register. */
#define PPC_RESP_ERR_LOCK               ((uint32_t)(1UL << 31U))
/** \brief The bit mask of enabling the response error disable feature. */
#define PPC_RESP_ERR_DIS_ENABLE         ((uint32_t)(1UL))
/** \brief The address of the response error disable register. */
#define FIREWALL_PPC_PESP_ERR_DIS_ADDR(base, apbmuxId)                         \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_RESP_ERR_DIS_OFFSET)

/** \brief The offset address of the interrupt status register. */
#define PPC_FUNC_INT_STA_OFFSET        ((uint32_t)0xE00U)
/** \brief The bit mask of the register error interrupt. */
#define PPC_FUNC_INT_STA_REG_RES_ERR   ((uint32_t)(1UL << 1))
/** \brief The bit mask of the peripheral error interrupt. */
#define PPC_FUNC_INT_STA_PER_RES_ERR   ((uint32_t)(1UL))
/** \brief The address of the interrupt status register for different apbmuxs.
 */
#define FIREWALL_PPC_FUNC_INT_STA_ADDR(base, apbmuxId)                         \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_FUNC_INT_STA_OFFSET)

/** \brief The offset address of the interrupt enable register. */
#define PPC_FUNC_INT_STA_EN_OFFSET      ((uint32_t)0xE04U)
/** \brief The bit mask of enabling the register error interrupt. */
#define PPC_FUNC_INT_STA_EN_REG_RES_ERR ((uint32_t)(1UL << 1))
/** \brief The bit mask of enabling the peripheral error interrupt. */
#define PPC_FUNC_INT_STA_EN_PER_RES_ERR ((uint32_t)(1UL))
/** \brief The address of the interrupt enable register for different apbmuxs.
 */
#define FIREWALL_PPC_FUNC_INT_STA_EN_ADDR(base, apbmuxId)                      \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_FUNC_INT_STA_EN_OFFSET)

/** \brief The offset address of the interrupt signal register. */
#define PPC_FUNC_INT_SIG_EN_OFFSET      ((uint32_t)0xE08U)
/** \brief The bit mask of enabling the register error interrupt signal. */
#define PPC_FUNC_INT_SIG_EN_REG_RES_ERR ((uint32_t)(1UL << 1))
/** \brief The bit mask of enabling the peripheral error interrupt signal. */
#define PPC_FUNC_INT_SIG_EN_PER_RES_ERR ((uint32_t)(1UL))
/** \brief The address of the interrupt signal register for different apbmuxs.
 */
#define FIREWALL_PPC_FUNC_INT_SIG_EN_ADDR(base, apbmuxId)                      \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_FUNC_INT_SIG_EN_OFFSET)

/** \brief The offset bit of privilege mode permission for domain0. */
#define FIREWALL_PPC_DOM0_PRIVILEGED_BIT  (4U)
/** \brief The offset bit of user mode permission for domain0. */
#define FIREWALL_PPC_DOM0_USER_BIT        (6U)
/** \brief The offset bit of privilege mode permission for domain1. */
#define FIREWALL_PPC_DOM1_PRIVILEGED_BIT  (12U)
/** \brief The offset bit of user mode permission for domain1. */
#define FIREWALL_PPC_DOM1_USER_BIT        (14U)
/** \brief The offset bit of privilege mode permission for domain2. */
#define FIREWALL_PPC_DOM2_PRIVILEGED_BIT  (20U)
/** \brief The offset bit of user mode permission for domain2. */
#define FIREWALL_PPC_DOM2_USER_BIT        (22U)
/** \brief The offset bit of privilege mode permission for domain3. */
#define FIREWALL_PPC_DOM3_PRIVILEGED_BIT  (28U)
/** \brief The offset bit of user mode permission for domain3. */
#define FIREWALL_PPC_DOM3_USER_BIT        (30U)
/** \brief The offset bit of privilege mode permission for domain4. */
#define FIREWALL_PPC_DOM4_PRIVILEGED_BIT  (4U)
/** \brief The offset bit of user mode permission for domain4. */
#define FIREWALL_PPC_DOM4_USER_BIT        (6U)
/** \brief The offset bit of privilege mode permission for domain5. */
#define FIREWALL_PPC_DOM5_PRIVILEGED_BIT  (12U)
/** \brief The offset bit of user mode permission for domain5. */
#define FIREWALL_PPC_DOM5_USER_BIT        (14U)
/** \brief The offset bit of privilege mode permission for domain6. */
#define FIREWALL_PPC_DOM6_PRIVILEGED_BIT  (20U)
/** \brief The offset bit of user mode permission for domain6. */
#define FIREWALL_PPC_DOM6_USER_BIT        (22U)
/** \brief The offset bit of privilege mode permission for domain7. */
#define FIREWALL_PPC_DOM7_PRIVILEGED_BIT  (28U)
/** \brief The offset bit of user mode permission for domain7. */
#define FIREWALL_PPC_DOM7_USER_BIT        (30U)
/** \brief The offset bit of privilege mode permission for domain8. */
#define FIREWALL_PPC_DOM8_PRIVILEGED_BIT  (4U)
/** \brief The offset bit of user mode permission for domain8. */
#define FIREWALL_PPC_DOM8_USER_BIT        (6U)
/** \brief The offset bit of privilege mode permission for domain9. */
#define FIREWALL_PPC_DOM9_PRIVILEGED_BIT  (12U)
/** \brief The offset bit of user mode permission for domain9. */
#define FIREWALL_PPC_DOM9_USER_BIT        (14U)
/** \brief The offset bit of privilege mode permission for domain10. */
#define FIREWALL_PPC_DOM10_PRIVILEGED_BIT (20U)
/** \brief The offset bit of user mode permission for domain10. */
#define FIREWALL_PPC_DOM10_USER_BIT       (22U)
/** \brief The offset bit of privilege mode permission for domain11. */
#define FIREWALL_PPC_DOM11_PRIVILEGED_BIT (28U)
/** \brief The offset bit of user mode permission for domain11. */
#define FIREWALL_PPC_DOM11_USER_BIT       (30U)
/** \brief The offset bit of privilege mode permission for domain12. */
#define FIREWALL_PPC_DOM12_PRIVILEGED_BIT (4U)
/** \brief The offset bit of user mode permission for domain12. */
#define FIREWALL_PPC_DOM12_USER_BIT       (6U)
/** \brief The offset bit of privilege mode permission for domain13. */
#define FIREWALL_PPC_DOM13_PRIVILEGED_BIT (12U)
/** \brief The offset bit of user mode permission for domain13. */
#define FIREWALL_PPC_DOM13_USER_BIT       (14U)
/** \brief The offset bit of privilege mode permission for domain14. */
#define FIREWALL_PPC_DOM14_PRIVILEGED_BIT (20U)
/** \brief The offset bit of user mode permission for domain14. */
#define FIREWALL_PPC_DOM14_USER_BIT       (22U)
/** \brief The offset bit of privilege mode permission for domain15. */
#define FIREWALL_PPC_DOM15_PRIVILEGED_BIT (28U)
/** \brief The offset bit of user mode permission for domain15. */
#define FIREWALL_PPC_DOM15_USER_BIT       (30U)

/** \brief The maximum number of regions in one apbmux. */
#define FIREWALL_PPC_APBMUXREGION_MAXNUM  (16U)
/** \brief The maximum number of regions in PPC module. */
#define FIREWALL_PPC_REGION_MAXNUM                                             \
    (FIREWALL_PPC_APBMUXREGION_MAXNUM * FIREWALL_PPC_APBMUX_MAXNUM)

/** \brief The bit mask of 1bit MPC registers. */
#define PPC_REG_BIT1_MASK           ((uint32_t)1U)
/** \brief The bit mask of 2bit MPC registers. */
#define PPC_REG_BIT2_MASK           ((uint32_t)2U)
/** \brief The width of 1bit MPC registers. */
#define PPC_REG_BIT1_WIDTH          (1U)
/** \brief The width of 2bit MPC registers. */
#define PPC_REG_BIT2_WIDTH          (2U)

/** \brief The address offset of the response error inverse register. */
#define PPC_RESP_ERR_DIS_INV        ((uint32_t)0x718U)
/** \brief The address of the response error disable inverse register. */
#define FIREWALL_PPC_PESP_ERR_DIS_ADDR_INV(base, apbmuxId)                     \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_RESP_ERR_DIS_INV)

/** \brief The address offset of the response error inverse register. */
#define PPC_REG_CFG_CMP_EN          ((uint32_t)0x71CU)
/** \brief The address of APB configuration compare register. */
#define FIREWALL_PPC_REG_CFG_CMP_EN_ADDR(base, apbmuxId)                       \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_REG_CFG_CMP_EN)
/** \brief The start bit of locking reg compare configuration. */
#define PPC_REG_CFG_CMP_LOCK        (31U)
/** \brief The start bit of locking reg compare configuration inverse. */
#define PPC_REG_CFG_CMP_LOCK_INV    (30U)
/** \brief The srart bit of enabling reg compare configuration inverse. */
#define PPC_REG_CFG_CMP_ENABLE_INV  (1U)
/** \brief The srart bit of enabling reg compare configuration. */
#define PPC_REG_CFG_CMP_ENABLE      (0U)

/** \brief The offset of the RGN_START_ADDR_INV register. */
#define PPC_RGN_START_ADDR_INV(n)   (uint32_t)((0x734U + ((uint32_t)(n)*0x08U)))
/** \brief The address of start address inverse register. */
#define FIREWALL_PPC_RGN_START_REG_ADDR_INV(base, apbmuxId, regionId)          \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
        PPC_APBMUX_OFFSET(apbmuxId) + PPC_RGN_START_ADDR_INV(regionId))

/** \brief The offset of the RGN_END_ADDR_INV register. */
#define PPC_RGN_END_ADDR_INV(n)     (uint32_t)((0x730U + ((uint32_t)(n)*0x08U)))
/** \brief The address of end address inverse register. */
#define FIREWALL_PPC_RGN_END_REG_ADDR_INV(base, apbmuxId, regionId)            \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
        PPC_APBMUX_OFFSET(apbmuxId) + PPC_RGN_END_ADDR_INV(regionId))

/** \brief The offset of the DOM_PER_LOCK_INV register. */
#define PPC_DOM_PER_LOCK_INV(n)     ((uint32_t)(0x7B0U + ((uint32_t)(n)*0x04U)))
/** \brief The address of the ppc permission lock inverse register
 * for differet peripherals or apb regions. */
#define FIREWALL_PPC_DOM_PER_LOCK_ADDR_INV(base, apbmuxId, ipId)               \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER_LOCK_INV(ipId))

/** \brief The offset of domain 0~3 permissions inverse register. */
#define PPC_DOM_PER0_INV(n)         ((uint32_t)(0x90CU + ((uint32_t)(n)*0x10U)))
/** \brief The offset of domain 4~7 permissions inverse register. */
#define PPC_DOM_PER1_INV(n)         ((uint32_t)(0x908U + ((uint32_t)(n)*0x10U)))
/** \brief The offset of domain 8~11 permissions inverse register. */
#define PPC_DOM_PER2_INV(n)         ((uint32_t)(0x904U + ((uint32_t)(n)*0x10U)))
/** \brief The offset of domain 12~15 permissions inverse register. */
#define PPC_DOM_PER3_INV(n)         ((uint32_t)(0x900U + ((uint32_t)(n)*0x10U)))

/** \brief The address of the ppc permission0 inverse register for
 * differet peripherals or apb regions. */
#define FIREWALL_PPC_DOMPER0_ADDR_INV(base, apbmuxId, ipId)                    \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET +                               \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER0_INV(ipId))

/** \brief The address of the ppc permission1 inverse register for
 * differet peripherals or apb regions. */
#define FIREWALL_PPC_DOMPER1_ADDR_INV(base, apbmuxId, ipId)                    \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET  +                              \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER1_INV(ipId))

/** \brief The address of the ppc permission2 inverse register for
 * differet peripherals or apb regions. */
#define FIREWALL_PPC_DOMPER2_ADDR_INV(base, apbmuxId, ipId)                    \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET  +                              \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER2_INV(ipId))

/** \brief The address of the ppc permission3 inverse register for
 * differet peripherals or apb regions. */
#define FIREWALL_PPC_DOMPER3_ADDR_INV(base, apbmuxId, ipId)                    \
    ((uint32_t)(base) + PPC_APBMUX_BASE_OFFSET  +                              \
     PPC_APBMUX_OFFSET(apbmuxId) + PPC_DOM_PER3_INV(ipId))

#if (defined(CFG_PLATFORM_MCAL))
#define FIREWALL_START_SEC_CODE
#include "Firewall_MemMap.h"
#endif /** #if (defined(CFG_PLATFORM_MCAL)) */

/***************************************************************************************************
 *                                  Private Function Declarations                                  *
 **************************************************************************************************/
/**
 * brief Disable the error response feature in the PPC module.
 *
 * This function disable the error response to bus of illegal accessing to
 * peripherals in the PPC module.
 * This function should be called if FIREWALL_RESPONSE_ERROR_EN is disable.
 *
 * param[in] base the address of the MAC module.
 */
static void Firewall_PpcResponseErrDisable(uint32_t base);

/**
 * brief Get the PPC lock status.
 *
 * param[in] base  The base address of the firewall
 * param[in] apbmux_id  The id of the apbmux
 * param[in] ip_id  The id of the ip id in the apbmux
 * param[in] is_region  Is the ip region check
 * param[in] ip_maxnum  The maximum number of ip in the apbmux
 * param[in] region_id  The id of the region
 *
 * return The state of the check result.
 */
static inline bool Firewall_PpcLockStatusCheck(uint32_t base, uint16_t apbmux_id,
                                                      uint16_t ip_id, bool is_region,
                                                      uint16_t ip_maxnum, uint16_t region_id);

/***************************************************************************************************
 *                                  Global Function Declarations                                   *
 **************************************************************************************************/
/**
 * \brief Configure the permission of peripherals in PPC module.
 *
 * This function configure the permission of peripherals in PPC module.
 * The permissions of peripherals in PPC module will be locked after
 * configuring. This function controls the features of interrupt and error
 * response according to the macro configuration.
 *
 * \param[in] base the address of the MAC module.
 * \param[in] ppc_cfg  The configuration of the apbmux IP permission.
 * \param[in] ip_num  The number of ip.
 *
 * \return The result of the PPC initialization function
 * \details - return FIREWALL_E_OK : Configurate PPC ip permission success.
 *          - return FIREWALL_E_NULL_POINTER : The pointer is a NULL_PTR.
 *          - return FIREWALL_E_PPC_IP_NUM : The number of peripherals is
 * unvalid.
 */
lld_status_t Firewall_PpcIpConfigure(const Firewall_ControllerType *ctrl,
                                        const Firewall_PpcIpConfigType *ppc_cfg,
                                        uint16_t ip_num)
{
    lld_status_t ret_val = (lld_status_t)FIREWALL_E_OK;
    uint32_t base = ctrl->macBaseAddr;
    uint32_t temp_val;
    uint16_t num;

    if (NULL == ppc_cfg)
    {
        ret_val = (lld_status_t)FIREWALL_E_NULL_POINTER;
    }
    else if (FIREWALL_PPC_IP_MAXNUM < ip_num)
    {
        ret_val = (lld_status_t)FIREWALL_E_PPC_IP_NUM;
    }
    else
    {
        for (num = 0; num < ip_num; num++)
        {
            if (true == Firewall_PpcLockStatusCheck(base,
                        (uint16_t)ppc_cfg[num].ppcApbmuxId,
                        (uint16_t)ppc_cfg[num].ppcApbmuxIpId,
                        false, 0U, 0U))
            {
                continue;
            }

            /* DOM0 all permissions is open */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain0PrivilegedPermission
                       << FIREWALL_PPC_DOM0_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain0UserPermission
                        << FIREWALL_PPC_DOM0_USER_BIT;

            /* DOM1 all permission is close */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain1PrivilegedPermission
                        << FIREWALL_PPC_DOM1_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain1UserPermission
                        << FIREWALL_PPC_DOM1_USER_BIT;

            /* DOM2 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain2PrivilegedPermission
                        << FIREWALL_PPC_DOM2_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain2UserPermission
                        << FIREWALL_PPC_DOM2_USER_BIT;

            /* DOM3 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain3PrivilegedPermission
                        << FIREWALL_PPC_DOM3_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain3UserPermission
                        << FIREWALL_PPC_DOM3_USER_BIT;

            /* DOM0 ~ DOM3 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER0_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM0 ~ DOM3 inverse permission register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER0_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM4 permission */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain4PrivilegedPermission
                       << FIREWALL_PPC_DOM4_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain4UserPermission
                        << FIREWALL_PPC_DOM4_USER_BIT;

            /* DOM5 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain5PrivilegedPermission
                        << FIREWALL_PPC_DOM5_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain5UserPermission
                        << FIREWALL_PPC_DOM5_USER_BIT;

            /* DOM6 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain6PrivilegedPermission
                        << FIREWALL_PPC_DOM6_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain6UserPermission
                        << FIREWALL_PPC_DOM6_USER_BIT;

            /* DOM7 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain7PrivilegedPermission
                        << FIREWALL_PPC_DOM7_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain7UserPermission
                        << FIREWALL_PPC_DOM7_USER_BIT;

            /* DOM4 ~ DOM7 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER1_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM4 ~ DOM7 inverse permission register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER1_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM8 permission */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain8PrivilegedPermission
                       << FIREWALL_PPC_DOM8_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain8UserPermission
                        << FIREWALL_PPC_DOM8_USER_BIT;

            /* DOM9 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain9PrivilegedPermission
                        << FIREWALL_PPC_DOM9_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain9UserPermission
                        << FIREWALL_PPC_DOM9_USER_BIT;

            /* DOM10 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain10PrivilegedPermission
                        << FIREWALL_PPC_DOM10_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain10UserPermission
                        << FIREWALL_PPC_DOM10_USER_BIT;

            /* DOM11 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain11PrivilegedPermission
                        << FIREWALL_PPC_DOM11_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain11UserPermission
                        << FIREWALL_PPC_DOM11_USER_BIT;

            /* DOM8 ~ DOM11 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER2_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM8 ~ DOM11 inverse permission register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER2_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM12 permission */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain12PrivilegedPermission
                        << FIREWALL_PPC_DOM12_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain12UserPermission
                        << FIREWALL_PPC_DOM12_USER_BIT;

            /* DOM13 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain13PrivilegedPermission
                        << FIREWALL_PPC_DOM13_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain13UserPermission
                        << FIREWALL_PPC_DOM13_USER_BIT;

            /* DOM14 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain14PrivilegedPermission
                        << FIREWALL_PPC_DOM14_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain14UserPermission
                        << FIREWALL_PPC_DOM14_USER_BIT;

            /* DOM15 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain15PrivilegedPermission
                        << FIREWALL_PPC_DOM15_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain15UserPermission
                        << FIREWALL_PPC_DOM15_USER_BIT;

            /* DOM12 ~ DOM15 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER3_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* DOM12 ~ DOM15 inverse permission register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER3_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* Lock domain permissions of all apb regions. */
            writel(PPC_PERMISSION_LOCK_MASK,
                    FIREWALL_PPC_DOM_PER_LOCK_ADDR(
                        base,
                        (uint32_t)ppc_cfg[num].ppcApbmuxId,
                        (uint32_t)ppc_cfg[num].ppcApbmuxIpId));

            /* Set lock domain permission inverse register fot safety mechanism. */
            writel(~PPC_PERMISSION_LOCK_MASK,
                    FIREWALL_PPC_DOM_PER_LOCK_ADDR_INV(
                        base,
                        (uint32_t)ppc_cfg[num].ppcApbmuxId,
                        (uint32_t)ppc_cfg[num].ppcApbmuxIpId));
        }
    }

    if (1U == ctrl->interruptEnable)
    {
        /* #30 Turn on inturrupt when illegal access. */
        Firewall_PpcInterruptEnable(base, true);
    } /* else not needed */

    if (1U != ctrl->resErrEnable)
    {
        /* #40 Disable respone error when illegal access. */
        Firewall_PpcResponseErrDisable(base);
    }/* else not needed */

    return ret_val;
}

/**
 * \brief Configure the permission of peripherals' regions in PPC module.
 *
 * This function configure the permission of peripherals' regions in PPC module.
 * The permissions of regions will be locked after configuring.
 * This function controls the features of interrupt and error response according
 * to the macro configuration.
 *
 * \param[in] base the address of the MAC module.
 * \param[in] ppc_cfg  The configuration of the apbmux addr permission.
 * \param[in] region_num  The number of address region.
 *
 * \return The result of the PPC initialization function
 * \details - return FIREWALL_E_OK : Configurate PPC ip permission success.
 *          - return FIREWALL_E_NULL_POINTER : The pointer is a NULL_PTR.
 *          - return FIREWALL_E_PPC_REGION_NUM : The number of peripherals'
 *                                                regions is unvalid.
 */
lld_status_t Firewall_PpcAddrConfigure(const Firewall_ControllerType *ctrl,
               const Firewall_PpcAddrConfigType *ppc_cfg, uint16_t region_num)
{
    lld_status_t ret_val = (lld_status_t)FIREWALL_E_OK;
    uint32_t base = ctrl->macBaseAddr;
    uint16_t num;
    uint16_t region_maxnum;
    uint32_t temp_val;

    if (NULL == ppc_cfg)
    {
        ret_val = (lld_status_t)FIREWALL_E_NULL_POINTER;
    }
    else if (FIREWALL_PPC_REGION_MAXNUM < region_num)
    {
        ret_val = (lld_status_t)FIREWALL_E_PPC_REGION_NUM;
    }
    else
    {
        for (num = 0; num < region_num; num++)
        {
            region_maxnum = Firewall_PpcGetApbmuxIpMaxnum(
                (uint8_t)ppc_cfg[num].ppcApbmuxId);

            if (true == Firewall_PpcLockStatusCheck(base,
                        (uint16_t)ppc_cfg[num].ppcApbmuxId,
                        0U, true, region_maxnum,
                        (uint16_t)ppc_cfg[num].ppcRegionN))
            {
                continue;
            }

            /* DOM0 all permissions is open */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain0PrivilegedPermission
                       << FIREWALL_PPC_DOM0_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain0UserPermission
                        << FIREWALL_PPC_DOM0_USER_BIT;

            /* DOM1 all permission is close */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain1PrivilegedPermission
                        << FIREWALL_PPC_DOM1_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain1UserPermission
                        << FIREWALL_PPC_DOM1_USER_BIT;

            /* DOM2 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain2PrivilegedPermission
                        << FIREWALL_PPC_DOM2_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain2UserPermission
                        << FIREWALL_PPC_DOM2_USER_BIT;

            /* DOM3 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain3PrivilegedPermission
                        << FIREWALL_PPC_DOM3_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain3UserPermission
                        << FIREWALL_PPC_DOM3_USER_BIT;

            /* DOM0 ~ DOM3 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER0_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));
            /* DOM0 ~ DOM3 permission reverse register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER0_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));

            /* DOM4 permission */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain4PrivilegedPermission
                       << FIREWALL_PPC_DOM4_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain4UserPermission
                        << FIREWALL_PPC_DOM4_USER_BIT;

            /* DOM5 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain5PrivilegedPermission
                        << FIREWALL_PPC_DOM5_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain5UserPermission
                        << FIREWALL_PPC_DOM5_USER_BIT;

            /* DOM6 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain6PrivilegedPermission
                        << FIREWALL_PPC_DOM6_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain6UserPermission
                        << FIREWALL_PPC_DOM6_USER_BIT;

            /* DOM7 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain7PrivilegedPermission
                        << FIREWALL_PPC_DOM7_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain7UserPermission
                        << FIREWALL_PPC_DOM7_USER_BIT;

            /* DOM4 ~ DOM7 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER1_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));
            /* DOM4 ~ DOM7 permission reverse register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER1_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));

            /* DOM8 permission */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain8PrivilegedPermission
                       << FIREWALL_PPC_DOM8_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain8UserPermission
                        << FIREWALL_PPC_DOM8_USER_BIT;

            /* DOM9 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain9PrivilegedPermission
                        << FIREWALL_PPC_DOM9_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain9UserPermission
                        << FIREWALL_PPC_DOM9_USER_BIT;

            /* DOM10 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain10PrivilegedPermission
                        << FIREWALL_PPC_DOM10_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain10UserPermission
                        << FIREWALL_PPC_DOM10_USER_BIT;

            /* DOM11 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain11PrivilegedPermission
                        << FIREWALL_PPC_DOM11_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain11UserPermission
                        << FIREWALL_PPC_DOM11_USER_BIT;

            /* DOM9 ~ DOM11 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER2_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));
            /* DOM9 ~ DOM11 permission reverse register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER2_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));

            /* DOM12 permission */
            temp_val = (uint32_t)ppc_cfg[num].ppcDomain12PrivilegedPermission
                        << FIREWALL_PPC_DOM12_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain12UserPermission
                        << FIREWALL_PPC_DOM12_USER_BIT;

            /* DOM13 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain13PrivilegedPermission
                        << FIREWALL_PPC_DOM13_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain13UserPermission
                        << FIREWALL_PPC_DOM13_USER_BIT;

            /* DOM14 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain14PrivilegedPermission
                        << FIREWALL_PPC_DOM14_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain14UserPermission
                        << FIREWALL_PPC_DOM14_USER_BIT;

            /* DOM15 permission */
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain15PrivilegedPermission
                        << FIREWALL_PPC_DOM15_PRIVILEGED_BIT;
            temp_val |= (uint32_t)ppc_cfg[num].ppcDomain15UserPermission
                        << FIREWALL_PPC_DOM15_USER_BIT;

            /* DOM12 ~ DOM15 permission set */
            writel(temp_val,
                   FIREWALL_PPC_DOMPER3_ADDR(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));
            /* DOM12 ~ DOM15 permission reverse register set */
            writel((~temp_val),
                   FIREWALL_PPC_DOMPER3_ADDR_INV(
                       base,
                       (uint32_t)ppc_cfg[num].ppcApbmuxId,
                       (uint32_t)ppc_cfg[num].ppcRegionN +
                           (uint32_t)region_maxnum));

            /* Lock domain permissions of all apb regions. */
            writel(PPC_PERMISSION_LOCK_MASK,
                    FIREWALL_PPC_DOM_PER_LOCK_ADDR(
                        base,
                        ppc_cfg[num].ppcApbmuxId,
                        ppc_cfg[num].ppcRegionN +
                            (uint32_t)region_maxnum));
            writel((~PPC_PERMISSION_LOCK_MASK),
                    FIREWALL_PPC_DOM_PER_LOCK_ADDR_INV(
                        base,
                        ppc_cfg[num].ppcApbmuxId,
                        ppc_cfg[num].ppcRegionN +
                            (uint32_t)region_maxnum));

            /* Configure address range. */
            RMWREG32(
                FIREWALL_PPC_RGN_START_REG_ADDR(base, ppc_cfg[num].ppcApbmuxId,
                                                      ppc_cfg[num].ppcRegionN),
                PPC_RGN_START_ADDR_BIT,
                PPC_RGN_START_ADDR_WIDTH,
                PPC_REGION_ADDR(ppc_cfg[num].ppcStartAddr));
            RMWREG32(
                FIREWALL_PPC_RGN_END_REG_ADDR(base, ppc_cfg[num].ppcApbmuxId,
                                                    ppc_cfg[num].ppcRegionN),
                PPC_RGN_END_ADDR_BIT,
                PPC_RGN_END_ADDR_WIDTH,
                PPC_REGION_ADDR(ppc_cfg[num].ppcEndAddr));

            /* Configure the address range reverse registers. */
            RMWREG32(
                FIREWALL_PPC_RGN_START_REG_ADDR_INV(base, ppc_cfg[num].ppcApbmuxId,
                                                    ppc_cfg[num].ppcRegionN),
                PPC_RGN_START_ADDR_BIT,
                PPC_RGN_START_ADDR_WIDTH,
                (~PPC_REGION_ADDR(ppc_cfg[num].ppcStartAddr)));
            RMWREG32(
                FIREWALL_PPC_RGN_END_REG_ADDR_INV(base, ppc_cfg[num].ppcApbmuxId,
                                                    ppc_cfg[num].ppcRegionN),
                PPC_RGN_END_ADDR_BIT,
                PPC_RGN_END_ADDR_WIDTH,
                (~PPC_REGION_ADDR(ppc_cfg[num].ppcEndAddr)));

            /* Lock the region addr range configuration.*/
            RMWREG32(
                FIREWALL_PPC_RGN_END_REG_ADDR(base, ppc_cfg[num].ppcApbmuxId,
                                                    ppc_cfg[num].ppcRegionN),
                PPC_RGN_END_ADDR_LOCK_BIT,
                PPC_REG_BIT1_WIDTH,
                PPC_REG_BIT1_MASK);
            RMWREG32(
                FIREWALL_PPC_RGN_END_REG_ADDR_INV(base, ppc_cfg[num].ppcApbmuxId,
                                                    ppc_cfg[num].ppcRegionN),
                PPC_RGN_END_ADDR_LOCK_BIT,
                PPC_REG_BIT1_WIDTH,
                ((~PPC_REG_BIT1_MASK) & PPC_REG_BIT1_MASK));

            /* Enable and lock the region's configuration. */
            RMWREG32(
                FIREWALL_PPC_RGN_ADDR_ENABLE_REG_ADDR(base, ppc_cfg[num].ppcApbmuxId,
                                                        ppc_cfg[num].ppcRegionN),
                PPC_RGN_ENABLE,
                PPC_REG_BIT2_WIDTH,
                PPC_REG_BIT1_MASK);

            RMWREG32(
                FIREWALL_PPC_RGN_ADDR_ENABLE_REG_ADDR(base, ppc_cfg[num].ppcApbmuxId,
                                                        ppc_cfg[num].ppcRegionN),
                PPC_RGN_ENABLE_LOCK_INV,
                PPC_REG_BIT2_WIDTH,
                PPC_REG_BIT2_MASK);
        }
    }

    if (1U == ctrl->interruptEnable)
    {
        /* #30 Turn on inturrupt when illegal access. */
        Firewall_PpcInterruptEnable(base, true);
    } /* else not needed */

    if (1U != ctrl->resErrEnable)
    {
        /* #40 Disable respone error when illegal access. */
        Firewall_PpcResponseErrDisable(base);
    }/* else not needed */

    return ret_val;
}

/**
 * \brief Get the interrupt status of the PPC module.
 *
 * This function get the illegal access error information of the PPC module.
 * The function exits as soon as it gets an illegal access message.
 * This function should be called by the firewall interrupt handler
 * Firewall_IrqHandler().
 *
 * \param[in] base the address of the MAC module.
 *
 *  \return The illegal access error status of the PPC module.
 */
Firewall_PpcIrqStaType Firewall_PpcIrqHandler(uint32_t base)
{
    Firewall_PpcIrqStaType IrqSta = {0U};
    uint8_t apbmux_num;
    uint32_t sta_enable;
    uint32_t sig_enable;

    for (apbmux_num = 0; apbmux_num < FIREWALL_PPC_APBMUX_MAXNUM; ++apbmux_num)
    {
        /* Get the interrupt status of the apbmux. */
        IrqSta.ppcErrSta =
            (readl(FIREWALL_PPC_FUNC_INT_STA_ADDR(base, apbmux_num)) &
             (PPC_FUNC_INT_STA_REG_RES_ERR |
              PPC_FUNC_INT_STA_PER_RES_ERR));

        if (0U < IrqSta.ppcErrSta)
        {
            /* Clear the interrupt status of the apbmux. */
            writel((uint32_t)IrqSta.ppcErrSta,
                   FIREWALL_PPC_FUNC_INT_STA_ADDR(base, apbmux_num));

            sta_enable =
                readl(FIREWALL_PPC_FUNC_INT_STA_EN_ADDR(base, apbmux_num));
            sig_enable =
                readl(FIREWALL_PPC_FUNC_INT_SIG_EN_ADDR(base, apbmux_num));
            if (0U ==
                ((uint32_t)IrqSta.ppcErrSta & sta_enable & sig_enable))
            {
                IrqSta.ppcErrSta = 0U;
            }
            else
            {
                IrqSta.ppcApbmuxId = apbmux_num;
            }

            break;
        } /* else not needed */
    }

    return IrqSta;
}

/**
 * \brief Clear the interrupt status of the PPC module.
 *
 * This function clear the interrupt status of the PPC module.
 *
 * \param[in] base the base address of the MAC module.
 */
void Firewall_PpcClearInterrupt(uint32_t base)
{
    uint8_t apbmux_num;

    /* #10 Clear the interrupt of all apbmuxs. */
    for (apbmux_num = 0U; apbmux_num < FIREWALL_PPC_APBMUX_MAXNUM; ++apbmux_num)
    {
        /* Disable the interrupt signal of the apbmux. */
        writel(FIREWALL_REG_VALUE_MIN,
               FIREWALL_PPC_FUNC_INT_SIG_EN_ADDR(base, apbmux_num));
        /* Disable the interrupt of the apbmux. */
        writel(FIREWALL_REG_VALUE_MIN,
               FIREWALL_PPC_FUNC_INT_STA_EN_ADDR(base, apbmux_num));
        /* Clear the interrupt status of the apbmux. */
        writel(FIREWALL_REG_VALUE_MAX,
               FIREWALL_PPC_FUNC_INT_STA_ADDR(base, apbmux_num));
    }
}

/**
 * \brief Control the interrupt of illegal accessing for the PPC module.
 *
 * \param[in] base the address of the MAC module.
 * \param[in] enable Enable or disable the firewall interrupts
 */
void Firewall_PpcInterruptEnable(uint32_t base, bool enable)
{
    uint8_t apbmux_num;
    uint32_t sta_val;
    uint32_t sig_val;

    /* #10 Get the state and signal value */
    sta_val = (true == enable) ?
              (PPC_FUNC_INT_STA_EN_PER_RES_ERR | PPC_FUNC_INT_STA_EN_REG_RES_ERR) :
               0U;
    sig_val = (true == enable) ?
              (PPC_FUNC_INT_SIG_EN_PER_RES_ERR | PPC_FUNC_INT_SIG_EN_REG_RES_ERR) :
               0U;

    /* #10 Turn on inturrupt when illegal access. */
    for (apbmux_num = 0; apbmux_num < FIREWALL_PPC_APBMUX_MAXNUM; ++apbmux_num)
    {
        writel(sta_val, FIREWALL_PPC_FUNC_INT_STA_EN_ADDR(base, apbmux_num));
        writel(sig_val, FIREWALL_PPC_FUNC_INT_SIG_EN_ADDR(base, apbmux_num));
    }
}

/**
 * brief Enable Apb conguration compare feature in the PPC module.
 *
 * This function enable the Apb conguration compare in the PPC module.
 * This function should be called by Firewall_PpcAddrConfigure.
 *
 * param[in] base the address of the MAC module.
 */
void Firewall_PpcRegCompEnable(uint32_t base)
{
    uint8_t apbmux_num;

    /* #10 Disable respone error when illegal access, and lock this
     * configuarion. */
    for (apbmux_num = 0; apbmux_num < FIREWALL_PPC_APBMUX_MAXNUM; ++apbmux_num)
    {
            /* #20 Enable and lock MPC register compare for safety mechanism. */
            RMWREG32(FIREWALL_PPC_REG_CFG_CMP_EN_ADDR(base, apbmux_num),
                PPC_REG_CFG_CMP_ENABLE, PPC_REG_BIT2_WIDTH, PPC_REG_BIT1_MASK );

            RMWREG32(FIREWALL_PPC_REG_CFG_CMP_EN_ADDR(base, apbmux_num),
                PPC_REG_CFG_CMP_LOCK_INV, PPC_REG_BIT2_WIDTH, PPC_REG_BIT2_MASK);
    }
}

/***************************************************************************************************
 *                                  Private Function Declarations                                  *
 **************************************************************************************************/
/**
 * brief Disable the error response feature in the PPC module.
 *
 * This function disable the error response to bus of illegal accessing to
 * peripherals in the PPC module.
 * This function should be called if FIREWALL_RESPONSE_ERROR_EN is disable.
 *
 * param[in] base the address of the MAC module.
 */
static void Firewall_PpcResponseErrDisable(uint32_t base)
{
    uint8_t apbmux_num;

    /* #10 Disable respone error when illegal access, and lock this
     * configuarion. */
    for (apbmux_num = 0; apbmux_num < FIREWALL_PPC_APBMUX_MAXNUM; ++apbmux_num)
    {
        /* Disable respone error. */
        writel(PPC_RESP_ERR_DIS_ENABLE,
                FIREWALL_PPC_PESP_ERR_DIS_ADDR(base, apbmux_num));
        writel((~PPC_RESP_ERR_DIS_ENABLE),
                FIREWALL_PPC_PESP_ERR_DIS_ADDR_INV(base, apbmux_num));

        /* lock the configuarion. */
        writel(PPC_RESP_ERR_DIS_ENABLE | PPC_RESP_ERR_LOCK,
                FIREWALL_PPC_PESP_ERR_DIS_ADDR(base, apbmux_num));
        writel(~(PPC_RESP_ERR_DIS_ENABLE | PPC_RESP_ERR_LOCK),
                FIREWALL_PPC_PESP_ERR_DIS_ADDR_INV(base, apbmux_num));
    }
}

/**
 * brief Get the PPC lock status.
 *
 * param[in] base  The base address of the firewall
 * param[in] apbmux_id  The id of the apbmux
 * param[in] ip_id  The id of the ip id in the apbmux
 * param[in] is_region  Is the ip region check
 * param[in] ip_maxnum  The maximum number of ip in the apbmux
 * param[in] region_id  The id of the region
 *
 * return The state of the check result.
 */
static inline bool Firewall_PpcLockStatusCheck(uint32_t base, uint16_t apbmux_id,
                                                      uint16_t ip_id, bool is_region,
                                                      uint16_t ip_maxnum, uint16_t region_id)
{
    bool ret_val = false;
    uint16_t ppc_reg_index;

    /* #10 Caculate the index of the register. */
    ppc_reg_index = (true == is_region) ? (ip_maxnum + region_id) : ip_id;
    /* #20 Check the state of the permission. */
    if (PPC_PERMISSION_LOCK_MASK == (PPC_PERMISSION_LOCK_MASK &
        readl(FIREWALL_PPC_DOM_PER_LOCK_ADDR(base, apbmux_id, ppc_reg_index))))
    {
        ret_val = true;
    }

    /* #30 Check the state of the address if the config is ip region. */
    if (true == is_region)
    {
        if (PPC_RGN_END_ADDR_LOCK == (PPC_RGN_END_ADDR_LOCK &
            readl(FIREWALL_PPC_RGN_END_REG_ADDR(base, apbmux_id, region_id))))
        {
            ret_val = true;
        }

        if (PPC_RGN_ENABLE_LOCK == (PPC_RGN_ENABLE_LOCK &
            readl(FIREWALL_PPC_RGN_ADDR_ENABLE_REG_ADDR(base, apbmux_id, region_id))))
        {
            ret_val = true;
        }
    }

    return ret_val;
}

#if (defined(CFG_PLATFORM_MCAL))
#define FIREWALL_STOP_SEC_CODE
#include "Firewall_MemMap.h"
#endif /** #if (defined(CFG_PLATFORM_MCAL)) */

#ifdef __cplusplus
}
#endif

/* End of file */
